#!/usr/bin/perl

=head1 NAME

Revamped - A flexible content management system.

=head1 SYNOPSIS

    http://[URI]/

Coming soon.

=head1 DESCRIPTION

Revamped is designed to be a very flexible content management system.

=head1 CAVEATS

* Headers are not sent appropriately

=head1 TODO

* Image uploader

=head1 AUTHORS

Alan Haggai Alavi <alanhaggai@alanhaggai.org>

=head1 LICENSE

This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself. See L<http://www.perl.com/perl/misc/Artistic.html>.

=head1 AVAILABILITY

alanhaggai.org - L<http://alanhaggai.org>

=cut


# Use Data::Dumper or YAML or Storable to read a pre-defined configuration file.

use strict;
use warnings;
use Template;
use CGI qw/:standard/;
use CGI::Carp qw/fatalsToBrowser/;
use DBI;
use Data::Dumper;
use Storable;

$| = 1;

my $template = Template->new({
    INCLUDE_PATH => 'template',
    EVAL_PERL    => 1,
    LOAD_PERL    => 1,
    DEBUG        => 1,
});

my %database = (
    username => 'root',
    password => ''
);

my $dbh = DBI->connect('DBI:mysql:revamped', $database{username}, $database{password}) or die DBI->errstr;
my $sth = $dbh->prepare('SELECT `page_protect`, `page_title`, `page_manual` FROM `pages` ORDER BY `pages`.`page_order` ASC') or die DBI->errstr;
$sth->execute or die DBI->errstr;

# Populate pages and links
my (@pages, @protected, @manual);
while (my @row = $sth->fetchrow_array()) {
        push @manual, $row[1] if $row[2] == 1;
        push @protected, $row[1] if $row[0] == 1;
        push @pages, $row[1];
}

my @links = map {
    my ($temp, $flag) = ($_, 0);
    for (@protected) {
        $flag = 1 if $_ eq $temp;
    }
    $temp =~ s/-/~/g;
    $temp =~ s/ /-/g;
    [$_, $temp] unless $flag == 1;
} @pages;

my($login, $create, $error, $status) = (0, 0);

if(param('module') eq 'login') {
    &authenticate;
} elsif(param('module') eq 'create') {
    &check_authentication;
    if($login == 1) {
        &create
    } else {
        $error = 'Page creation failed due to authentication failure.';
    }
    my $title = param('title');
    $title =~ s/-/~/g;
    $title =~ s/ /-/g;
    print redirect(-uri => "index.pl?$title");
} elsif(param('module') eq 'update') {
    &update;
    my $title = param('title');
    $title =~ s/-/~/g;
    $title =~ s/ /-/g;
    $status = 'The page was updated successfully.';
    print redirect(-uri => "index.pl?$title");
} elsif(param('module') eq 'menu-editor') {
    &menu_editor; 
    print redirect(-uri => 'index.pl?Menu-Editor');
} elsif(param('module') eq 'image-pool') {
    &image_pool;
    print redirect(-uri => 'index.pl?Image-Pool');
} else {
    print header;
}

$login = 1 if cookie('authentication');

my $file = 'template.tmpl';
my $vars = {
    title     => 'Revamped',
    links     => \@links,
    pages     => \@pages,
    protected => \@protected,
    manual    => \@manual,
    cgi       => CGI->new(),
    page      => $ENV{QUERY_STRING},
    login     => $login,
    create    => $create,
    error     => $error,
    status    => $status,
    debug     => 1,
    database  => {
        username => $database{username},
        password => $database{password},
    },
    software => {
        name    => 'Revamped',
        version => '0.1.4',
        author  => 'Alan Haggai Alavi',
        email   => 'alanhaggai@alanhaggai.org',
        website => 'http://alanhaggai.org',
        uri     => 'http://localhost/revamped',
    },
};

$template->process($file, $vars) or die $template->error();

sub authenticate {
    # I should add more `death' messages ;-)

    my $sth = $dbh->prepare('SELECT * FROM `login` WHERE `username` = ? AND `password` = ?');
    $sth ->execute(param('username'), param('password')) or die 'Died executing';
    
    if($sth->rows) {
        my $cookie = cookie(
            -name    => 'authentication',
            -value   => param('username'),
            -expires => '+1h'
        );
        $login = 1;
        $status = 'You have been given the authentication passport.';
        print header(-cookie => $cookie);
    } else {
        print header;
        $error = 'Authentication failed!';
        $login = 0;
    }

}

sub create {
    $create = 1;
    
    $error = 'Title cannot be empty. Specify please.' if param('title');

    my $sth = $dbh->prepare('SELECT `page_order` FROM `pages` ORDER BY `pages`.`page_order` DESC LIMIT 1');
    $sth ->execute or die DBI->errstr;
    my $order = $sth->fetchrow_array + 1;

    $sth = $dbh->prepare('SELECT `page_id` FROM `pages` ORDER BY `pages`.`page_id` DESC LIMIT 1');
    $sth ->execute or die DBI->errstr;
    my $id = $sth->fetchrow_array + 1;

    $sth = $dbh->prepare('INSERT INTO `revamped`.`pages` (`page_id`, `page_title` , `page_content`, `page_order`) VALUES (?, ?, ?, ?);');
    $sth ->execute($id, param('title'), param('content'), $order) or die DBI->errstr;

    $status = 'Page has been created successfully.';
}

sub check_authentication { cookie('authentication') ? $login = 1 : $login = 0 }

sub update {
    my $sth = $dbh->prepare('UPDATE `revamped`.`pages` SET `page_title` = ?, `page_content` = ? WHERE CONVERT( `pages`.`page_id` USING utf8 ) = ?') or die DBI->errstr;
    $sth ->execute(param('title'), param('content'), param('id')) or die DBI->errstr;

    $status = 'Page has been updated successfully.';
}

sub menu_editor {
    my (@titles, $flag);
    my @temp = param();
    my @titles;

    for (1 .. (@temp / 3)) {
        my ($order, undef, $title) = (param(shift @temp), param(shift @temp), param(shift @temp));
        push @titles, [$order, $title];
    }

    my ($query, $sth);

    # Rearrange the remaining items if any of the items have been deleted.
    my ($i, $j, $skip);
    map {
        $i++;
        if($_->[0] == 0) {
            $j = $i;
            $skip++;
        }
        $_->[0] -= $skip if $i > $j;
    } @titles;

    map {
        if($_->[0] == 0) {
            $sth = $dbh->prepare('DELETE FROM `pages` WHERE CONVERT(`pages`.`page_title` USING utf8) = ?') or die DBI->errstr; 
            $sth->execute($_->[1]) or die DBI->errstr;
        } else {
            $sth = $dbh->prepare('UPDATE `revamped`.`pages` SET `page_order` = ? WHERE CONVERT( `pages`.`page_title` USING utf8 ) = ?') or die DBI->errstr; 
            $sth->execute($_->[0], $_->[1]) or die DBI->errstr;
        }
    } @titles;
}

sub image_pool {
    my $image = param('image');

    if($image =~ /[\.jpg|\.png|\.gif|\.bmp]$/) {
        open FH, '>images/' . param('image');
        while (<$image>) { print FH $_ }
        close FH;
    }

    # Somehow make the status available
    #   * One way is to write to a temporary file and read it later on.
}
